/*
 * WSART.java
 *
 * Revision:
 * Author                                       	Date           
 * ---------------------------------------------	------------   
 * Francisco Gomes de Oliveira Neto					05/02/2013
 */
package br.edu.ufcg.splab.techniques.regression;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import br.edu.ufcg.splab.core.InterfaceEdge;
import br.edu.ufcg.splab.generator.TestCase;
import br.edu.ufcg.splab.generator.TestSuite;
import br.edu.ufcg.splab.util.Facade;

public class WSART {
	
	private TestSuite obsolete;
	private TestSuite retestable;
	private TestSuite reusable;
	private double[][] matrix;

	public List<TestCase> select(TestSuite baselineTS, TestSuite deltaTS){
		matrix = generateMatrix(baselineTS, deltaTS);
		analyzeMatrix(matrix, baselineTS, deltaTS);
		return selectFromMatrix(matrix, baselineTS, deltaTS);
		//generate matrix
		//classify test cases
		//get weights
		//select test cases.
	}
	
	public double[][] generateMatrix(TestSuite baselineTS, TestSuite deltaTS){
		double[][] matrix = new double[deltaTS.size()][baselineTS.size()];
		for (int i = 0; i < deltaTS.size(); i++) {
			TestCase deltaTC = deltaTS.get(i);
			for (int j = 0; j < baselineTS.size(); j++) {
				TestCase baselineTC = baselineTS.get(j);
				double similarity = getSimilarity(deltaTC, baselineTC);
				matrix[i][j] = similarity;
			}
		}
		
		//printMatrix(matrix);
		return matrix;
	}

	public String printMatrix() {
		DecimalFormat df = new DecimalFormat("#0.00");
		String eol = System.getProperty("line.separator");
		StringBuffer matrixSTR = new StringBuffer();
		
		for (int i = 0; i < matrix.length; i++) {
			for (int j = 0; j < matrix[i].length; j++) {
				if(matrix[i][j] == 0.0){
					matrixSTR.append("-.--");
				}else{
					matrixSTR.append(df.format(matrix[i][j]));	
				}
				
				matrixSTR.append(" ");
			}
			matrixSTR.append(eol);
		}
		return matrixSTR.toString();
		
	}

	private void analyzeMatrix(double[][] matrix, TestSuite baseline, TestSuite delta){
		obsolete = new TestSuite();
		retestable = new TestSuite();
		reusable = new TestSuite();
		
		for (int column = 0; column < matrix[0].length; column++) {
			boolean isObsolete = true;
			for (int row = 0; row < matrix.length; row++) {
				if(matrix[row][column] == 1.0){
					//non-obsolete
					isObsolete = false;
					row = matrix.length; //skip to next column
				}				
			}
			if(isObsolete){
				obsolete.add(baseline.get(column));
			}
		}
		
		for (int i = 0; i < matrix.length; i++) {
			boolean isRetestable = true;
			for (int j = 0; j < matrix[i].length; j++) {
				if(matrix[i][j] == 1.0){
					isRetestable = false;
					j = matrix[i].length;
				}
			}
			if(isRetestable){
				retestable.add(delta.get(i));
			}else{
				reusable.add(delta.get(i));
			}
		}
		
//		System.out.println("Obsolete: ");
//		printList(obsolete);
//		System.out.println("Reusable: ");
//		printList(reusable);
//		System.out.println("Retestable: ");
//		printList(retestable);
		
	}
	
	private List<TestCase> selectFromMatrix(double[][] matrix, TestSuite baseline, TestSuite delta){
		List<TestCase> obsolete = new ArrayList<TestCase>();
		List<TestCase> retestable = new ArrayList<TestCase>();
		List<TestCase> reusable = new ArrayList<TestCase>();
		
		for (int column = 0; column < matrix[0].length; column++) {
			boolean isObsolete = true;
			double highestSimilarity = matrix[0][column];
			int mostSimilarIndex = 0;
			for (int row = 0; row < matrix.length; row++) {
				if(matrix[row][column] > highestSimilarity){
					highestSimilarity = matrix[row][column];
					mostSimilarIndex = row;
				}
				if(matrix[row][column] == 1.0){
					//non-obsolete
					isObsolete = false;
					row = matrix.length; //skip to next column
				}				
			}
			if(isObsolete && !obsolete.contains(delta.get(mostSimilarIndex))){
				obsolete.add(delta.get(mostSimilarIndex));
			}
		}
		
		retestable.addAll(obsolete);
		for (int i = 0; i < matrix.length; i++) {
			boolean isRetestable = true;
			for (int j = 0; j < matrix[i].length; j++) {
				if(matrix[i][j] == 1.0){
					isRetestable = false;
					j = matrix[i].length;
				}				
			}
			if(isRetestable && !retestable.contains(delta.get(i))){
				retestable.add(delta.get(i));
			}
		}
		
		return retestable;
	}

	
	private void printList(List<TestCase> suite) {
		for(TestCase tc : suite){
			System.out.println(tc);
		}
		System.out.println();
	}

	private double getSimilarity(TestCase tc1, TestCase tc2) {
		List<InterfaceEdge> transitions1 = tc1.getTestCase();
		List<InterfaceEdge> transitions2 = tc2.getTestCase();
		
		//Number of Identical Transitions
		double nit = 0;
		for(InterfaceEdge transition1 : transitions1){			
			for (int i = 0; i < transitions2.size(); i++) {
				InterfaceEdge transition2 = transitions2.get(i);
//				if(transition1.getLabel().equals(transition2.getLabel()) &&
//						transition1.getFrom().getLabel().equals(transition2.getFrom().getLabel()) &&
//						transition1.getTo().getLabel().equals(transition2.getTo().getLabel())){
				if(transition1.getLabel().equals(transition2.getLabel())){
					nit = nit + 1.0; 
					i = transitions2.size(); //skip to the next transition.
				}
			}			
		}
		double avgSize = (double)(transitions1.size()+transitions2.size())/2.0;
		double similarity = nit/avgSize;
		return similarity;
	}

	
	public TestSuite getObsolete() {
		return obsolete;
	}

	public TestSuite getRetestable() {
		return retestable;
	}

	public TestSuite getReusable() {
		return reusable;
	}
}
